﻿using System;
using System.Collections.Generic;
using DatabaseGroup.SSIS.SourceAdapters.View;
using DatabaseGroup.SSIS.SourceAdapters.Model;

namespace DatabaseGroup.SSIS.SourceAdapters.Presenter
{
    /// <summary>
    /// Presenter for handling the Column tab view
    /// </summary>
    public class ColumnTabPresenter
    {
        private readonly IEditorColumnView _view;
        private readonly ISourceFileModel _fileModel;
        private readonly IComponentModel _componentModel;
        private ColumnTabSettings _settings;

        /// <summary>
        /// Initializes a new instance of the ColumnTabPresenter class
        /// using the view, fileModel, and propertiesModel
        /// </summary>
        /// <param name="view">An instance of an IEditorColumnView</param>
        /// <param name="componentModel">An instance of an IComponentModel</param>
        /// <param name="fileModel">An instance of an ISourceFileModel</param>
        public ColumnTabPresenter(IEditorColumnView view, IComponentModel componentModel, ISourceFileModel fileModel)
        {
            _view = view;
            _fileModel = fileModel;
            _componentModel = componentModel;

            InitializeView();

            view.ViewSettings += view_ViewSettings;
            view.SavingSettings += view_SavingSettings;
            view.MainDelimitersChanged += view_MainDelimitersChanged;
            view.ResetColumns += view_ResetColumns;
        }

        /// <summary>
        /// Saves the current settings to the component metadata
        /// </summary>
        /// <param name="sender">The View</param>
        /// <param name="e"></param>
        private void view_SavingSettings(object sender, EventArgs e)
        {
            _componentModel.SetProperty(PropertiesManager.RowDelimiterPropName, DelimiterStringConverter.ToValueDelim(_settings.RowDelimiter));
            _componentModel.SetProperty(PropertiesManager.ColumnDelimiterPropName, DelimiterStringConverter.ToValueDelim(_settings.ColumnDelimiter));
        }

        /// <summary>
        /// Binds the view with the current settings object
        /// </summary>
        /// <param name="sender">The View</param>
        /// <param name="e"></param>
        private void view_ViewSettings(object sender, TabEventArgs e)
        {
            if (e.Tab != EditorViewTab.Columns && e.Tab != EditorViewTab.ANY)
                return;

            _view.BindColumnTab(_settings);
            
            if (ValidateSettings())
                PopulatePreviewRows();
        }

        /// <summary>
        /// Validates the updated values for the column/row delimiters
        /// </summary>
        /// <param name="sender">The View</param>
        /// <param name="e"></param>
        private void view_MainDelimitersChanged(object sender, EventArgs e)
        {
            ValidateSettings();
        }

        /// <summary>
        /// Resets the standard output column configurations
        /// based on the current settings
        /// </summary>
        /// <param name="sender">The View</param>
        /// <param name="e"></param>
        private void view_ResetColumns(object sender, EventArgs e)
        {
            if (!ValidateSettings())
                return;

            // TODO: MessageStrings
            if (!_view.RequestUserConfirmation("Please confirm you wish to reset all configured columns," +
                    Environment.NewLine + "this will result in any current column confirguration being lost."))
                return;

            GeneralTabSettings generalTabSettings = _view.GetTabSettings<GeneralTabSettings>(EditorViewTab.General);
            AttemptStandardOutputColumnConfigurationFromFile(generalTabSettings.ColumnNamesInFirstDataRow);
            PopulatePreviewRows();
        }

        /// <summary>
        /// Creates a new column settings object and loads it with the current
        /// component configuration and binds it to the view
        /// </summary>
        private void InitializeView()
        {
            _settings = new ColumnTabSettings();

            _settings.RowDelimiter =
                DelimiterStringConverter.ToReadableDelim(_componentModel.GetProperty<string>(PropertiesManager.RowDelimiterPropName));
            _settings.ColumnDelimiter =
                DelimiterStringConverter.ToReadableDelim(_componentModel.GetProperty<string>(PropertiesManager.ColumnDelimiterPropName));

            _view.BindColumnTab(_settings);
        }

        /// <summary>
        /// Looks at the first row of the source file and attempts to
        /// create standard output columns named using the column data
        /// </summary>
        /// <param name="columnNamesInFirstRow">True if the first data row should be used to create the column names from</param>
        private void AttemptStandardOutputColumnConfigurationFromFile(bool columnNamesInFirstRow)
        {
            PresenterUtils.ConfigureFileModel(_fileModel, _componentModel, _view);
            List<string[]> rows = new List<string[]>();
            GeneralTabSettings generalTabSettings = _view.GetTabSettings<GeneralTabSettings>(EditorViewTab.General);

            if (_componentModel.IsFileConnectionValid(generalTabSettings.FileConnection))
                rows = _fileModel.GetRows(0, 1, false);

            AdvanceTabSettings advanceTabSettings = _view.GetTabSettings<AdvanceTabSettings>(EditorViewTab.Advance);

            if (rows.Count == 1)
            {
                string[] names = new string[rows[0].Length];

                if (columnNamesInFirstRow)
                {
                    names = rows[0];
                }
                else
                {
                    for (int colIndex = 0; colIndex < names.Length; colIndex++)
                    {
                        names[colIndex] = "Column " + (colIndex + 1);
                    }
                }

                BuildColumnsFromNames(advanceTabSettings.Columns, names);
            }
            else
            {
                // failed to parse column names from file, so reset columns
                advanceTabSettings.Columns.Clear();
            }
        }

        /// <summary>
        /// Loads an initial sample of source file rows and 
        /// populates the Column tab with them
        /// </summary>
        private void PopulatePreviewRows()
        {
            PresenterUtils.ConfigureFileModel(_fileModel, _componentModel, _view);
            GeneralTabSettings generalTabSettings = _view.GetTabSettings<GeneralTabSettings>(EditorViewTab.General);

            List<string> headers = new List<string>();
            List<string[]> rowHeaders = new List<string[]>();

            if (_componentModel.IsFileConnectionValid(generalTabSettings.FileConnection))
                rowHeaders = _fileModel.GetRows(0, 1, false);

            if (generalTabSettings.ColumnNamesInFirstDataRow && rowHeaders.Count > 0)
            {
                headers = new List<string>(rowHeaders[0]);
            }

            if (headers.Count < 1 && rowHeaders.Count > 0 && rowHeaders[0].Length > 0)
            {
                for (int headerIndex = 0; headerIndex < rowHeaders[0].Length; headerIndex++)
                {
                    // TODO: MessageStrings
                    headers.Add("Column " + (headerIndex + 1));
                }
            }

            List<string[]> rows = new List<string[]>();

            if (_componentModel.IsFileConnectionValid(generalTabSettings.FileConnection))
                rows = _fileModel.GetRows(0, 20, true);

            _view.PopulateColumnPreviewRows(headers, rows);
        }

        /// <summary>
        /// Validates the Column tab settings 
        /// </summary>
        /// <returns>True if settings are valid</returns>
        private bool ValidateSettings()
        {
            if (string.IsNullOrEmpty(_settings.ColumnDelimiter) || string.IsNullOrEmpty(_settings.RowDelimiter))
            {
                // TODO: MessageStrings
                _view.ShowErrorMessage("You must specify both delimiters.");
                return false;
            }

            _view.HideErrorMessage();
            return true;
        }

        /// <summary>
        /// Takes a list of column names and builds a list of ColumnProperties
        /// using the name along with default column properties
        /// </summary>
        /// <param name="columns">The list of columns to add to</param>
        /// <param name="columnNames">The list of column names to use</param>
        private void BuildColumnsFromNames(List<ColumnProperty> columns, string[] columnNames)
        {
            GeneralTabSettings generalSettings = _view.GetTabSettings<GeneralTabSettings>(EditorViewTab.General);
            bool useUnicode = PresenterUtils.ConvertStringToCodepage(generalSettings.CodePage) == 65001;

            if (generalSettings.IsUnicode)
                useUnicode = true;

            columns.Clear();
            
            foreach (string name in columnNames)
            {
                ColumnProperty column = PresenterUtils.CreateDefaultColumnProperty(useUnicode);
                column.Name = name;
                columns.Add(column);
            }
        }
    }
}
